#include <iostream>
#include <fstream>
#include <string>
#include "manager.h"

using namespace std;

// output primal mesh data to a file
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// IN: theMesh,nDim, meshFilename, iMesh
// OUT: ¨meshFilename¨_Primal.vtk
void outputPrimal(pMesh theMesh,const int &meshDim,const char *meshFilename, int iMesh, pMesh fineMesh)
{
	    // define names for the files
	    string str(meshFilename);
        string::size_type start = str.find_last_of("/");
        start = (start == string::npos)?0:start;
        string::size_type end = str.find_last_of(".");
        char buffer[256];
        memset( buffer, '\0', 256 );
        str.copy(buffer,end-start,start);
        char filename[256];
        sprintf(filename,"preprocessor-datafiles/%s_Primal.vtk",buffer);

	// open File
	ofstream meshFilePrimal;
	meshFilePrimal.open(filename);

	// check if the file was properly opened, and write data of the primal mesh
	if (meshFilePrimal.good())
	{
		int nNodePrimal = M_numVertices(fineMesh);

		meshFilePrimal<<"# vtk DataFile Version 2.0\nPrimal Mesh\nASCII\n";
		meshFilePrimal<<"DATASET UNSTRUCTURED_GRID\n";
		meshFilePrimal<<"POINTS "<<nNodePrimal<<" float\n";
		if (meshDim == 2) // 2-D
		{	// loop over nodes to write coordinates and define a sequential node ID,
			// as Gmsh supplies just a non-sequential node ID list
			int nodeId = 0;
			double coord[3] = {.0, .0, .0};
			VIter vit = M_vertexIter(fineMesh); // All meshes using node from fine mesh
			while (pEntity nodePrimal = VIter_next(vit))
			{
				V_coord(nodePrimal, coord);
				meshFilePrimal<<coord[0]<<" "<<coord[1]<<" 0.0\n"; //coordinates (x,y,0.0)
				EN_attachDataInt(nodePrimal,MD_lookupMeshDataId("Sequential ID"),nodeId);
				nodeId++;
			}
			VIter_delete(vit);

            if (iMesh ==-1)
            {
                int nFacePrimal = M_numFaces(theMesh);
                vector<pVertex> vertex;

                meshFilePrimal<<"CELLS "<<nFacePrimal<<" "<<nFacePrimal*4<<"\n";
                FIter fit = M_faceIter(theMesh);
                while (pEntity facePrimal = FIter_next(fit))
                { 	// loop over faces.Find its vertices,and after get its sequential IDs, so
                    // that its possible to write the nodes in the right manner on the vtk file
                    M_GetVertices(facePrimal,vertex);	// extract face's vertices

                    meshFilePrimal<<"3 ";
                    for (int i=0; i<3; i++)
                    {	// get sequential ID
                        int nodeId = 0;
                        EN_getDataInt(vertex[i],MD_lookupMeshDataId("Sequential ID"),&nodeId);
                        meshFilePrimal<<nodeId<<" ";
                    }
                    meshFilePrimal<<"\n";
                    vertex.clear();
                }
                FIter_delete(fit);
                meshFilePrimal<<"CELL_TYPES "<<nFacePrimal<<"\n";
                for (int i=0; i<nFacePrimal; i++) {
                    meshFilePrimal<<"5"<<"\n"; // elemType=5 => Triangle (vtk format)
                }
            }
            else
            {
                int nEdges = M_numEdges(theMesh);

                meshFilePrimal<<"CELLS "<<nEdges<<" "<<nEdges*3<<"\n";
                EIter fit = M_edgeIter(theMesh);
                while (pEntity edge = EIter_next(fit))
                { 	// loop over edges.Find its vertices,and after get its sequential IDs, so
                    // that its possible to write the nodes in the right manner on the vtk file

                    // Get edge´s node
                    pVertex node_1 = E_vertex(edge,0);
                    pVertex node_2 = E_vertex(edge,1);

                    meshFilePrimal<<"2 "<<EN_id(node_1)<<" "<<EN_id(node_2)<<"\n";

                }
                EIter_delete(fit);
                meshFilePrimal<<"CELL_TYPES "<<nEdges<<"\n";
                for (int i=0; i<nEdges; i++) {
                    meshFilePrimal<<"3"<<"\n"; // elemType=3 => Edge (vtk format)
                }
            }

		} else if (meshDim == 3) // 3-D
		{
			cout<<"The file "<<filename<<"could not be written in 3D!\n";
		}
		meshFilePrimal.close();
	} else
	{ // could not open the file
		cout<<"The file "<<filename<<"could not be opened!\n";
	}

}
// output dual mesh data to a file
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// IN: DIM_DUAL, CONNEC_DUAL, nNodeDual, nEdgeDual, nodeDual, edgeDual, meshFilename
// OUT: ¨meshFilename¨_Dual.vtk
void  outputDual(const int DIM_DUAL, const int CONNEC_DUAL, int nNodeDual, int nEdgeDual, float **nodeDual, int **edgeDual, const char *meshFilename)
{
	// define names for the files
	string str(meshFilename);
        string::size_type start = str.find_last_of("/");
        start = (start == string::npos)?0:start;
        string::size_type end = str.find_last_of(".");
        char buffer[256];
        memset( buffer, '\0', 256 );
        str.copy(buffer,end-start,start);
        char filename[256];
        sprintf(filename,"preprocessor-datafiles/%s_Dual.vtk",buffer);

	// open File
	ofstream meshFileDual;
	meshFileDual.open(filename);

	// check if the file was properly opened, and write data of the dual mesh
	if (meshFileDual.good())
	{
		meshFileDual<<"# vtk DataFile Version 2.0\nDual Mesh\nASCII\n";
		meshFileDual<<"DATASET UNSTRUCTURED_GRID\n";
		meshFileDual<<"POINTS "<<nNodeDual<<" float\n";
		if (DIM_DUAL == 2) // 2-D
		{
			for (int i=0; i<nNodeDual; i++)
			{
				meshFileDual<<nodeDual[i][0]<<" "<<nodeDual[i][1]<<" 0.0\n"; // coordinates (x,y,0.0)
			}
		} else if (DIM_DUAL == 3) // 3-D
		{
			for (int i=0; i<nNodeDual; i++)
			{
				meshFileDual<<nodeDual[i][0]<<" "<<nodeDual[i][1]<<
				" "<<nodeDual[i][2]<<"\n"; // coordinates (x,y,z)
			}
		}
		meshFileDual<<"CELLS "<<nEdgeDual<<" "<<nEdgeDual*3<<"\n";
		for (int i=0; i<nEdgeDual; i++) {
			meshFileDual<<"2 "<<edgeDual[i][0]<<" "<<edgeDual[i][1]<<"\n"; // connectivities
		}
		meshFileDual<<"CELL_TYPES "<<nEdgeDual<<"\n";
		for (int i=0; i<nEdgeDual; i++) {
			meshFileDual<<"3"<<"\n"; // elemType=3 => Edge (vtk format)
		}
		meshFileDual.close();
	} else
	{ // could not open the file
		cout<<"The file "<<filename<<"could not be opened!\n";
	}
}
